package myJs.detailInfo

import cats.effect.IO
import japgolly.scalajs.react.ScalaFnComponent
import japgolly.scalajs.react.util.EffectCatsEffect._
import japgolly.scalajs.react.vdom.all._
import myJs.Implicits._
import myJs.api.Api
import myJs.cps.BootstrapTableCp
import myJs.cps.BootstrapTableCp.Column
import myJs.myPkg.Hooks._
import myJs.myPkg.layer
import myJs.myPkg.reactBootstrap._
import myJs.tool.Pojo._
import myJs.tool.Tool
import shared.pojo.Browse._
import upickle.default._

import scala.collection.immutable.SeqMap
import scala.scalajs.js

/** Created by yz on 28/11/2023
  */
object CdsSnpCp {

  case class Props(id: String, hasChange: Boolean => IO[Unit])

  val Component = ScalaFnComponent[Props] { props =>
    val fileNamePrefix = s"snp.cds.info"

    val (datas, setDatas) = useState(List.empty[ujson.Obj])
    val (columns, setColumns) = useState(List.empty[Column])

    object FTool {

      def tbFmt(field: String) = (v: ujson.Value, row: ujson.Obj) => {
        field match {
          case "gene_id" =>
            a(href := s"https://www.ncbi.nlm.nih.gov/gene/?term=${v.str}", cursor.pointer, target := "_blank", v.str)
          case "ref_id" =>
            a(href := s"https://www.ncbi.nlm.nih.gov/protein/${v.str}", cursor.pointer, target := "_blank", v.str)
          case _ => span(v.myStr)()
        }
      }

      def comVFmt(fileTitle: String) = (v: ujson.Value, row: ujson.Obj) => {
        fileTitle match {
          case _ => v.myStr
        }
      }

      def refreshBasicData = {
        val request = GetFileData.Request(id = props.id, fileName = s"${fileNamePrefix}.xls")
        Api.browse.getMummerFileData(request).flatMap { response =>
          val curDatas = response.array
          val map = response.map
          val datas = curDatas.map(x => writeJs(x).transform(reader[ujson.Obj]))
          val basicColumns = map.map { case (k, v) =>
            val searchKind = v match {
              case _ => TextSearch
            }
            val title = v match {
              case _ => v
            }
            val fmt = FTool.tbFmt(v)
            val comVF = FTool.comVFmt(v)
            val optionMap = searchKind match {
              case _ => SeqMap[String, String]()
            }
            val operable = k match {
              case _ => true
            }
            val questionMap = SeqMap(
              "ref_id" -> "参考序列ID",
              "position" -> "SNP 的位置",
              "ref_base<->sample_base" -> "参考序列对应位置碱基 <-> 样品对应位置碱基，表示SNP 突变的碱基型",
              "snp_status" -> "SNP 类型，“Homo”表示纯合SNP，“Het 个数”，表示杂合SNP，杂合数为“Het”后的个数",
              "strand" -> "SNP 所在基因在参考序列上的方向",
              "codon_phase" -> "格式如“100:1”，“:”前表示该SNP 位点所在三联体密码子序号（起始密码子序号为1），“:”后表示该位点所在相位（“0”表示三联体密码子的第一位，“1”表示三联体密码子的第二位，“2”表示三联体密码子的第三位）",
              "codon_mutate" -> "SNP 所在的参考序列三联体密码子 <-> 样品三联体密码子",
              "aa_mutate" -> "SNP 所在的参考序列氨基酸 <-> 样品氨基酸",
              "mutate_type" -> "SNP 突变类型，“Synonymous”表示同义突变，“Nonsynonymous”表示非同义突变",
              "synonymous" -> "同义突变（“0”表示否，“1”表示是）",
              "nonsynonymous" -> "非同义突变（“0”表示否，“1”表示是）",
              "gene_id" -> "SNP 所在的参考序列的基因ID",
              "pos_start" -> "SNP 所在基因在参考序列上的起始位置",
              "pos_end" -> "SNP 所在基因在参考序列上的终止位置"
            )
            val titleE = v match {
              case x if (questionMap.isDefinedAt(x)) => {
                span(
                  v,
                  " ", {
                    val popover = Popover(id = "popover-basic")(
                      Popover.Header("说明"),
                      Popover.Body(
                        questionMap(v)
                      )
                    ).rawElement
                    OverlayTrigger(
                      placement = "auto",
                      trigger = js.Array("hover", "focus"),
                      overlay = popover
                    )(
                      span(
                        a(`type` := "button", i(className := "fa fa-question-circle"))
                      )
                    )
                  }
                )()
              }
              case x if !(List("OTU ID").contains(x)) =>
                span(
                  v
                )()
              case x => span(v)()
            }
            Column(
              field = k,
              title = title,
              operable = true,
              searchKind = searchKind,
              formatter = fmt,
              comVF = comVF,
              optionMap = optionMap,
              titleE = titleE
            )
          }.toList
          val curColumns = basicColumns
          setColumns(curColumns) >>
            setDatas(datas) >>
            props.hasChange(curColumns.nonEmpty)
        }
      }

    }

    useEffect(
      {
        FTool.refreshBasicData
      },
      List(props.id)
    )

    val exportDatas = List(
      ExportData("XLS", href = s"${Api.browse.downloadMummerFile(props.id, s"${fileNamePrefix}.xls")}")
    )

    div(
      h5(
        "Only the first 10,000 rows are displayed,the `XLS` Download  button in the upper right corner of the table will download all the data!"
      ),
      BootstrapTableCp
        .Props(
          columns = columns,
          datas = datas,
          showExport = true,
          exportData = exportDatas,
          search = true
        )
        .render
    )

  }

  def apply(id: String, hasChange: Boolean => IO[Unit]) = {
    Component(Props(id, hasChange))
  }

}
